package se.grp03.fmtuner.app;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.StringTokenizer;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TimePicker;
import android.widget.Toast;

public class MainActivity extends ActionBarActivity {

	private Button scanButton, tuneButton;
	private ArrayAdapter<String> channelListAdapter;
	private ListView channelList;
	private TimePicker timePicker;
	private String[] channels;
	private final String SCAN_MESSAGE = "scan";
	private Thread scanThread, tuneThread;
	private final String SCHEDULER_IP = "agile01.cs.newpaltz.edu";
	private final int SCHEDULER_PORT = 9001;
	private InetAddress schedulerAddress;
	private DatagramSocket schedulerSocket;
	private DatagramPacket schedulerPacket;
	private String channelToSend;
	private boolean channelToSendChosen;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		if (savedInstanceState == null) {
			getSupportFragmentManager().beginTransaction()
					.add(R.id.container, new PlaceholderFragment()).commit();
		}
		
		// Initialize Scheduler UDP communications
		Thread initThread = new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					schedulerAddress = InetAddress.getByName(SCHEDULER_IP);
				} catch (UnknownHostException e) {
					// TODO Auto-generated catch block
				}
			}
		});
		initThread.start();
		
		// Initialize list of channels.
		channels = new String[4];
		channels[0] = "92.7";
		channels[1] = "96.9";
		channels[2] = "101.5";
		channels[3] = "104.7";
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {

		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// Handle action bar item clicks here. The action bar will
		// automatically handle clicks on the Home/Up button, so long
		// as you specify a parent activity in AndroidManifest.xml.
		int id = item.getItemId();
		if (id == R.id.action_settings) {
			return true;
		}
		return super.onOptionsItemSelected(item);
	}
	
	@Override
	protected void onPostResume() {
		super.onPostResume();
		
		channelToSendChosen = false;
		
		scanButton = (Button) findViewById(R.id.scan_button);
		scanButton.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				scan(v);
			}
		});
		
		tuneButton = (Button) findViewById(R.id.tune_button);
		tuneButton.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				tune(v);
			}
		});
		
		channelList = (ListView) findViewById(R.id.channel_list);
		channelListAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, channels);
	    channelList.setAdapter(channelListAdapter);
		channelList.setOnItemClickListener(new OnItemClickListener() {
			@Override
			public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
				// TODO Auto-generated method stub
				channelToSend = (String) parent.getItemAtPosition(position);
				Log.d("Channel List", "\"" + channelToSend + "\" chosen.");
				channelToSendChosen = true;
			}
		});
		channelList.invalidateViews();
		
		timePicker = (TimePicker) findViewById(R.id.time_picker);
	}
	
	private void updateChannelList() {
		channelList.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, channels));
		//channelList.refreshDrawableState();
	}
	
	private void toastOnUIThread(final String msg) {		
		// Update channel list on UI thread.
        try {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                	Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();
                }
            });
            Thread.sleep(300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
	}

	/**
	 * A placeholder fragment containing a simple view.
	 */
	public static class PlaceholderFragment extends Fragment {

		public PlaceholderFragment() {
		}

		@Override
		public View onCreateView(LayoutInflater inflater, ViewGroup container,
				Bundle savedInstanceState) {
			View rootView = inflater.inflate(R.layout.fragment_main, container,
					false);
			return rootView;
		}
	}

	private void scan(View v) {
		scanThread = new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					// Send scan message to FM Tuner Agent.
					Log.d("UDP", "Outgoing message: " + SCAN_MESSAGE);
					schedulerSocket = new DatagramSocket();
					byte[] msgByte = (SCAN_MESSAGE).getBytes();
					DatagramPacket msgPacket = new DatagramPacket(msgByte, msgByte.length,
							schedulerAddress, SCHEDULER_PORT);
					schedulerSocket.send(msgPacket);
					Log.d("UDP", "Message sent!");
					
					// Accept incoming messages.
					ArrayList<String> newChannels = new ArrayList<String>();
					byte[] incByte = new byte[1024];
					DatagramPacket incPacket = new DatagramPacket(incByte, incByte.length);
					schedulerSocket.receive(incPacket);
					Log.d("UDP", "Incoming channels from " + incPacket.getAddress() + ":" + incPacket.getPort());
					String incomingMessage = new String(incPacket.getData(), 0, incPacket.getLength(), "UTF-8");
					StringTokenizer st = new StringTokenizer(incomingMessage);
					while (st.hasMoreTokens()) {
						// Add individual channels to list.
						String channel = st.nextToken();
						Log.d("UDP", "Incoming channel: " + channel);
						newChannels.add(channel);
					}
					Log.d("UDP", "Received all incoming channels!");
					
					// Replace local list of channels with new list.
					if(!newChannels.isEmpty()) {
						channels = new String[newChannels.size()];
						for(int x = 0; x < channels.length; x++)
							channels[x] = newChannels.get(x);
						
						// Update channel list on UI thread.
		                try {
		                    runOnUiThread(new Runnable() {
		                        @Override
		                        public void run() {
		                            updateChannelList();
		                        }
		                    });
		                    Thread.sleep(300);
		                } catch (InterruptedException e) {
		                    e.printStackTrace();
		                }
					}
				} catch (Exception e) {
					Log.d("UDP", "ERROR: " + e);
				} finally {
					schedulerSocket.close();
				}
			}
		});
        scanThread.start();
	}
	
	private void tune(View v) {
		if(channelToSendChosen) {
			tuneThread = new Thread(new Runnable() {
				@Override
				public void run() {
					try {
						// Build timestamp from TimePicker.
						String timestamp = (new Date()).toString();
						DecimalFormat df = new DecimalFormat("00");
						StringBuilder sb = new StringBuilder();
						sb.append(timestamp.substring(0, 11));
						sb.append(df.format(timePicker.getCurrentHour()));
						sb.append(':');
						sb.append(df.format(timePicker.getCurrentMinute()));
						sb.append(timestamp.substring(16));
						timestamp = sb.toString();
						
						// Send tune message to FM Tuner Agent.
						String tuneMessage = channelToSend + " " + sb.toString();
						/*Toast.makeText(getApplicationContext(), "Tune request for " + channelToSend 
								+ " at " + sb.toString() + "sent!", Toast.LENGTH_SHORT).show();*/
						Log.d("UDP", "Outgoing message: " + tuneMessage);
						schedulerSocket = new DatagramSocket();
						byte[] msgByte = (tuneMessage).getBytes();
						DatagramPacket msgPacket = new DatagramPacket(msgByte, msgByte.length,
								schedulerAddress, SCHEDULER_PORT);
						schedulerSocket.send(msgPacket);
						Log.d("UDP", "Message sent!");
						
						// Accept incoming messages.
						byte[] incByte = new byte[1024];
						DatagramPacket incPacket = new DatagramPacket(incByte, incByte.length);
						schedulerSocket.receive(incPacket);
						Log.d("UDP", "Incoming response from " + incPacket.getAddress() + ":" + incPacket.getPort());
						String incomingMessage = new String(incPacket.getData(), 0, incPacket.getLength(), "UTF-8");
						StringTokenizer st = new StringTokenizer(incomingMessage);
						if(st.hasMoreTokens()) {
							// Add individual channels to list.
							String response = st.nextToken();
							Log.d("UDP", "Incoming response: " + response);
							if(response.equalsIgnoreCase("ok")) {
								sb = new StringBuilder();
								sb.append("FM Radio will tune to ");
								sb.append(channelToSend);
								sb.append(" at ");
								sb.append(timestamp);
								toastOnUIThread(sb.toString());
								Log.d("UDP", "SUCCESS: Tune request completed.");
							}
							else {
								toastOnUIThread("! Tune request was unsuccessful. !");
								Log.d("UDP", "ERROR: Tune request failed.");
							}
						}
					} catch (Exception e) {
						Log.d("UDP", "ERROR: " + e);
					} finally {
						try {
							schedulerSocket.close();
						} catch (Exception e) {}
					}
				}
			});
	        tuneThread.start();			
		}
		else {
			Toast.makeText(getApplicationContext(), "Please choose an FM channel.", Toast.LENGTH_SHORT).show();
		}
	}
}
